/**
 * OWASP Enterprise Security API (ESAPI)
 *
 * This file is part of the Open Web Application Security Project (OWASP)
 * Enterprise Security API (ESAPI) project. For details, please see
 * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
 *
 * Copyright (c) 2008 - The OWASP Foundation
 *
 * The ESAPI is published by OWASP under the BSD license. You should read and accept the
 * LICENSE before you use, modify, and/or redistribute this software.
 *
 * @author Mike Fauzy <a href="http://www.aspectsecurity.com">Aspect Security</a>
 * @author Rogan Dawes <a href="http://www.aspectsecurity.com">Aspect Security</a>
 * @created 2008
 */
package org.owasp.esapi;



import org.owasp.esapi.util.ObjFactory;

/**
 * ESAPI locator class is provided to make it easy to gain access to the current ESAPI classes in use.
 * Use the set methods to override the reference implementations with instances of any custom ESAPI implementations.
 */
public final class ESAPI {
    private static String securityConfigurationImplName = System.getProperty("org.owasp.esapi.SecurityConfiguration", "org.owasp.esapi.reference.DefaultSecurityConfiguration");

    /**
     * prevent instantiation of this class
     */
    private ESAPI() {
    }



    /**
     * The ESAPI Encoder is primarilly used to provide <i>output</i> encoding to
     * prevent Cross-Site Scripting (XSS).
     * @return the current ESAPI Encoder object being used to encode and decode data for this application.
     */
    public static Encoder encoder() {
        return ObjFactory.make( securityConfiguration().getEncoderImplementation(), "Encoder" );
    }




    /**
     * Get the current LogFactory being used by ESAPI. If there isn't one yet, it will create one, and then
     * return this same LogFactory from then on.
     * @return The current LogFactory being used by ESAPI.
     */
    private static LogFactory logFactory() {
        return ObjFactory.make( securityConfiguration().getLogImplementation(), "LogFactory" );
    }

    /**
     * @param clazz The class to associate the logger with.
     * @return The current Logger associated with the specified class.
     */
    public static Logger getLogger(Class clazz) {
        return logFactory().getLogger(clazz);
    }

    /**
     * @param moduleName The module to associate the logger with.
     * @return The current Logger associated with the specified module.
     */
    public static Logger getLogger(String moduleName) {
        return logFactory().getLogger(moduleName);
    }

    /**
     * @return The default Logger.
     */
    public static Logger log() {
        return logFactory().getLogger("DefaultLogger");
    }



    private static volatile SecurityConfiguration overrideConfig = null;

    /**
     * @return the current ESAPI SecurityConfiguration being used to manage the security configuration for
     * ESAPI for this application.
     */
    public static SecurityConfiguration securityConfiguration() {
        // copy the volatile into a non-volatile to prevent TOCTTOU race condition
        SecurityConfiguration override = overrideConfig;
        if ( override != null ) {
            return override;
        }

        return ObjFactory.make( securityConfigurationImplName, "SecurityConfiguration" );
    }



    // TODO: This should probably use the SecurityManager or some value within the current
    // securityConfiguration to determine if this method is allowed to be called. This could
    // allow for unit tests internal to ESAPI to modify the configuration for the purpose of
    // testing stuff, and allow developers to allow this in development environments but make
    // it so the securityConfiguration implementation *cannot* be modified in production environments.
    //
    // The purpose of this method is to replace the functionality provided by the setSecurityConfiguration
    // method that is no longer on this class, and allow the context configuration of the ESAPI
    // to be modified at Runtime.
    public static String initialize( String impl ) {
        String oldImpl = securityConfigurationImplName;
        securityConfigurationImplName = impl;
        return oldImpl;
    }

    /**
     * Overrides the current security configuration with a new implementation. This is meant
     * to be used as a temporary means to alter the behavior of the ESAPI and should *NEVER*
     * be used in a production environment as it will affect the behavior and configuration of
     * the ESAPI *GLOBALLY*.
     *
     * To clear an overridden Configuration, simple call this method with null for the config
     * parameter.
     *
     * @param config The new security configuration.
     */
    public static void override( SecurityConfiguration config ) {
        overrideConfig = config;
    }
}
